package com.sz.app.edi.service.order.impl;

import com.sz.app.edi.rest.edi.base.LogisticsXMLRootRequest;
import com.sz.app.edi.service.constants.EdiCommCodes;
import com.sz.app.edi.constants.EdiErrorCodes;
import com.sz.app.edi.base.entity.SynCompanyAccount;
import com.sz.app.edi.base.entity.SynCompanyAccountSetting;
import com.sz.app.edi.exception.EdiExceptions;
import com.sz.app.edi.base.service.SynCompanyAccountService;
import com.sz.app.edi.base.service.SynCompanyAccountSettingService;
import com.sz.app.edi.rest.edi.base.EventBody;
import com.sz.app.edi.rest.edi.base.EventHead;
import com.sz.app.edi.rest.edi.base.LogisticsRequest;
import com.sz.app.edi.rest.edi.order.dto.SubOrder;
import com.sz.app.edi.rest.edi.track.dto.*;
import com.sz.app.edi.service.order.CusOrderTrackingService;
import com.sz.app.edi.rest.edi.AESOperator;
import com.sz.biz.common.constants.CommCodes;
import com.sz.biz.logistics.ord.dto.*;
import com.sz.biz.logistics.ord.service.*;
import com.sz.common.base.exception.Exceptions;
import com.sz.common.base.logger.Logger;
import com.sz.biz.logistics.constants.ErrorCodes;
import com.sz.biz.logistics.ord.entity.ConvertStatus;
import com.sz.biz.logistics.ord.entity.OrdTrackingMessage;
import com.sz.biz.logistics.ord.entity.OrdTrackingOriginal;
import com.sz.biz.logistics.ord.enums.TrackMessageToServiceEnum;
import com.sz.common.core.system.service.UnitConversionService;
import com.sz.common.base.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.*;

/**
 * Function: TODO: ADD FUNCTION <br>
 * Author: hpeng.wang. <br>
 * Date: 2017-07-04 14:27:00.
 */
@Service
public class CusOrderTrackingServiceImpl implements CusOrderTrackingService {
    public static final String KG = "kg";
    private Logger logger = Logger.getLogger(this.getClass());
    @Autowired
    private OrdOrderTrackingService orderTrackingService;
    @Autowired
    private OrdTrackingMessageService trackingMessageService;
    @Autowired
    private OrdTrackingOriginalService trackingOriginalService;
    @Autowired
    private OrdSubOrderService subOrderService;
    @Autowired
    private OrdOrderService orderService;
    @Autowired
    private SynCompanyAccountService synCompanyAccountService;
    @Autowired
    private SynCompanyAccountSettingService synCompanySettingService;
    @Autowired
    private UnitConversionService unitConversionService;


    /**
     * 第一个供应商给我们发的提货成功的物流消息
     *
     * @param orders     收到的dto信息
     * @param bizId
     * @param originalId
     */
    @Override
    public ConvertStatus processReceGoodTacking(Orders orders, int bizId, int originalId) {
        List<ReceGoodOrder> receGoodOrderList = orders.getOrder();
        List<OrdTrackingTransDto> trackingTransDtoList = new ArrayList<>();
        for (ReceGoodOrder receGoodOrder : receGoodOrderList) {
            //校验数据
            this.judgeVaild(receGoodOrder);
            //解析字符串日期为日期格式
            Date messageTime;
            messageTime = DateUtils.parseDetailDateTime(receGoodOrder.getMessageTime());

            //处理保存订单与子订单的重量与长宽高信息
            OrdTrackingTransDto trackingTransDto = new OrdTrackingTransDto();
            EntityUtils.copyPropertiesIgnoreNull(receGoodOrder, trackingTransDto);
            trackingTransDto.setMessageTime(messageTime);
            trackingTransDto.setSupplierId(bizId);
            trackingTransDto.setOriginalId(originalId);
            trackingTransDto.setTotalWeightUnit("kg");

            //拼装子订单
            List<OrdTrackingTransSubOrderDto> subOrderDtoList = new ArrayList<>();
            for (SubOrder subOrder : receGoodOrder.getSubOrder()) {
                OrdTrackingTransSubOrderDto trackingTransSubOrderDto = new OrdTrackingTransSubOrderDto();
                EntityUtils.copyPropertiesIgnoreNull(subOrder, trackingTransSubOrderDto);
                trackingTransSubOrderDto.setLwhUnit("m");
                trackingTransSubOrderDto.setWeightUnit("kg");
                subOrderDtoList.add(trackingTransSubOrderDto);
            }
            trackingTransDto.setSubOrder(subOrderDtoList);

            trackingTransDtoList.add(trackingTransDto);
        }
         orderTrackingService.processReceGoodTracking(trackingTransDtoList);
        return ConvertStatus.CONVERT_SUCCESS;
    }

    @Override
    public void processNormalTracking(String batchNo, ReceNormalOrders orders, Integer bizId, int originalId) {
        List<ReceNormalOrder> trackingList = orders.getOrder();

        List<OrderNormalTrackingDto> orderNormalTrackingDtoList = new ArrayList<>();
        Set<Integer> status = new HashSet<>();
        Set<String> code = new HashSet<>();
        for (ReceNormalOrder receNormalOrder : trackingList) {

            status.add(receNormalOrder.getStatus());
            code.add(receNormalOrder.getCode());

            Date messageTime;
            messageTime = DateUtils.parseDetailDateTime(receNormalOrder.getMessageTime());

            //处理保存订单与子订单的重量与长宽高信息
            OrderNormalTrackingDto orderNormalTrackingDto = new OrderNormalTrackingDto();
            EntityUtils.copyPropertiesIgnoreNull(receNormalOrder, orderNormalTrackingDto);

            orderNormalTrackingDto.setMessageTime(messageTime);
            orderNormalTrackingDto.setServiceOrderNo(receNormalOrder.getServiceOrderNo());
            orderNormalTrackingDto.setTrackMessage(receNormalOrder.getTrackMessage());
            orderNormalTrackingDto.setType(CommCodes.TRACKING_TYPE_SUPPER);
            orderNormalTrackingDto.setSubOrderNo(receNormalOrder.getSubOrderNo());
            orderNormalTrackingDto.setSupplierId(bizId);
            orderNormalTrackingDto.setOriginalId(originalId);
            orderNormalTrackingDtoList.add(orderNormalTrackingDto);
        }

        //如果是批次的情况下code与status应一样
        if (!StringUtils.isEmpty(batchNo)) {
            if (status.size() > 1) {
                logger.error("status异常" + trackingList.toString());
                throw EdiExceptions.ediException(EdiErrorCodes.ERROR_EDI_ORD_TRACKING_STATUS_ERROR);
            } else if (code.size() > 1) {
                logger.error("code异常" + trackingList.toString());
                throw EdiExceptions.ediException(EdiErrorCodes.ERROR_EDI_ORD_TRACKING_CODE_ERROR);
            }
        }

        orderTrackingService.processNomarlTracking(orderNormalTrackingDtoList, batchNo);
    }


    /**
     * 我们发送——给供应商发送揽货的物流消息
     *
     * @param ordTrackingMessageList
     * @param eventCode
     */
    @Override
    public void syncReceGoodInfo(List<OrdTrackingMessage> ordTrackingMessageList, TrackMessageToServiceEnum eventCode) {
        if (!CollectionUtils.isEmpty(ordTrackingMessageList)) {

            //拼装要处理的数据
            Map<Integer, SynCompanyAccount> synCompanyMap = new HashMap<>();
            Map<Object, List<OrdTrackingMessage>> trackingMessageMap = new HashMap<>();
            Map<String, SynCompanyAccountSetting> synCompanySettingMap = assembleData(ordTrackingMessageList, synCompanyMap, trackingMessageMap);
            List<OrdTrackingMessage> errorTrackingMessageList = new ArrayList<>();
            trackingMessageMap.forEach((obj, trackingMessageList) -> {

                //获取batchNo、synCompanyAccount
                SynCompanyAccount synCompanyAccount;
                String batchNo = "";
                int supperId;
                if (obj instanceof Integer) {
                    supperId = (int) obj;
                } else {
                    OrdTrackingMessage trackingMessage = trackingMessageList.get(0);
                    supperId = trackingMessage.getSupplierId();
                    batchNo = trackingMessage.getBatchNo();
                }
                if (supperId <= 0) {
                    logger.error("供应商未找到,物流的编号为：" + trackingMessageList.get(0).getId());
                }
                synCompanyAccount = synCompanyMap.get(supperId);
                if (!ObjectUtils.isEmpty(synCompanyAccount)) {
                    //拼装LogisticsEventsRequest
                    LogisticsXMLRootRequest eventsRequest = new LogisticsXMLRootRequest();
                    //拼装LogisticsEvent
                    LogisticsRequest LogisticsRequest = new LogisticsRequest();
                    eventsRequest.setLogisticsRequest(LogisticsRequest);
                    //拼装EventHead
                    EventHead eventHead = new EventHead();
                    eventHead.setEventTarget(synCompanyAccount.getClientId());
                    eventHead.setEventSource(EdiCommCodes.EVENT_SOURCE_HNA);
                    eventHead.setEventCode(eventCode.getCode());
                    eventHead.setEventTime(DateUtils.formatDetailDate(new Date()));
                    LogisticsRequest.setEventHead(eventHead);
                    //拼装EventBody
                    EventBody eventBody = new EventBody();
                    NoticeOrders orders = new NoticeOrders();
                    List<NoticeGoodOrder> noticeGoodOrderList = new ArrayList<>();
                    LinkedHashMap<String, Object> tradeDetail = new LinkedHashMap<>();
                    tradeDetail.put("batchNo", batchNo);
                    tradeDetail.put("orders", orders);
                    eventBody.setData(tradeDetail);
                    LogisticsRequest.setEventBody(eventBody);

                    this.generateNoticeGoodOrder(trackingMessageList, noticeGoodOrderList);
                    orders.setOrder(noticeGoodOrderList);
                    String synJson = JsonUtils.toJSONString(eventsRequest);

                    //判断是否需要加密
                    if (synCompanyAccount.getIsEncrypt() == 1) {
                        try {
                            synJson = AESOperator.getInstance().encrypt(synJson, synCompanyAccount.getKeySign());
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                    System.out.println(synJson);
                    SynCompanyAccountSetting synCompanyAccountSetting = synCompanySettingMap.get(synCompanyAccount.getClientId());
                    if (!StringUtils.isEmpty(synCompanyAccountSetting.getSynUrl())) {
                        //TODO 同步给供应商synJson
                    }
                    //同步完成后更新状态
                    List<Integer> ids = new ArrayList<>();
                    trackingMessageList.forEach(tracking -> ids.add(tracking.getId()));
                    trackingMessageService.updateStatusByIds(ids, 2);
                } else {
                    logger.error("供应商的id找不到" + supperId + "，在sys_company表中未配置");
                    errorTrackingMessageList.addAll(trackingMessageList);
                }
                //处理同步出错
                if (!CollectionUtils.isEmpty(errorTrackingMessageList)) {
                    List<Integer> ids = new ArrayList<>();
                    errorTrackingMessageList.forEach(trackingMessage -> ids.add(trackingMessage.getId()));
                    trackingMessageService.updateStatusByIds(ids, EdiCommCodes.ORD_ORDER_UNPLACE_ERROR_10000);//同步地址未找到
                    logger.error("同步出出错，ids为：" + ids);
                }

            });
        }

    }

    private void generateNoticeGoodOrder(List<OrdTrackingMessage> trackingMessageList, List<NoticeGoodOrder> noticeGoodOrderList) {
        for (OrdTrackingMessage trackingMessage : trackingMessageList) {
            NoticeGoodOrder noticeGoodOrder = new NoticeGoodOrder();
            OrderTrackingToServiceDto orderTrackingToServiceDto = JsonUtils.toObject(trackingMessage.getTrackingReport(), OrderTrackingToServiceDto.class);
            EntityUtils.copyPropertiesIgnoreNull(orderTrackingToServiceDto, noticeGoodOrder);
            noticeGoodOrder.setMessageTime(DateUtils.formatDetailDate(trackingMessage.getMessageTime()));
            noticeGoodOrder.setWaybillNo(orderTrackingToServiceDto.getWaybillNo());
            noticeGoodOrder.setCargoType(orderTrackingToServiceDto.getCargoTypeName());
            noticeGoodOrder.setPackageNum(orderTrackingToServiceDto.getPackageNum());
            noticeGoodOrder.setTotalWeight(orderTrackingToServiceDto.getWeight());
            noticeGoodOrder.setSendName(orderTrackingToServiceDto.getSenderName());
            noticeGoodOrder.setSendAddress(orderTrackingToServiceDto.getSenderAddress());
            noticeGoodOrder.setSendContact(orderTrackingToServiceDto.getSenderContact());
            noticeGoodOrder.setReceverName(orderTrackingToServiceDto.getReceiverName());
            noticeGoodOrder.setReceverAddress(orderTrackingToServiceDto.getReceiverAddress());
            noticeGoodOrder.setReceverContact(orderTrackingToServiceDto.getReceiverContact());

            //处理单位
            this.procesUnit(noticeGoodOrder, orderTrackingToServiceDto);


            noticeGoodOrderList.add(noticeGoodOrder);
        }
    }

    /**
     * 处理给供应商同步时，单位不是kg的情况
     *
     * @param noticeGoodOrder
     * @param orderTrackingToServiceDto
     */
    private void procesUnit(NoticeGoodOrder noticeGoodOrder, OrderTrackingToServiceDto orderTrackingToServiceDto) {
        //如果重量不是kg，转换成kg
        if (!KG.equalsIgnoreCase(orderTrackingToServiceDto.getWeightUnit())) {
            BigDecimal totalWeigth = unitConversionService.getTargetWeight(orderTrackingToServiceDto.getWeight(), orderTrackingToServiceDto.getWeightUnit(), "KG");
            noticeGoodOrder.setTotalWeight(totalWeigth);

        }
        //子订单处理
        for (OrdSubOrderDto subOrderDto : orderTrackingToServiceDto.getSubOrders()) {
            SubOrder subOrder = new SubOrder();
            EntityUtils.copyPropertiesIgnoreNull(subOrderDto, subOrder);
            noticeGoodOrder.addSubOrder(subOrder);
        }
    }

    private Map<String, SynCompanyAccountSetting> assembleData(List<OrdTrackingMessage> trackingMessageList, Map<Integer, SynCompanyAccount> synCompanyMap, Map<Object, List<OrdTrackingMessage>> trackingMessageMap) {
        List<Integer> supplierIdList = new ArrayList<>();
        for (OrdTrackingMessage trackingMessage : trackingMessageList) {
            //根据supperid或batchNo组装成map，然后批量向供应商下单
            if (!ObjectUtils.isEmpty(trackingMessage.getBatchNo())) {
                if (trackingMessageMap.get(trackingMessage.getBatchNo()) == null) {
                    trackingMessageMap.put(trackingMessage.getBatchNo(), new ArrayList<>());
                }
                trackingMessageMap.get(trackingMessage.getBatchNo()).add(trackingMessage);
            } else {
                if (trackingMessageMap.get(trackingMessage.getSupplierId()) == null) {
                    trackingMessageMap.put(trackingMessage.getSupplierId(), new ArrayList<>());
                }
                trackingMessageMap.get(trackingMessage.getSupplierId()).add(trackingMessage);
            }
            supplierIdList.add(trackingMessage.getSupplierId());
        }
        List<SynCompanyAccount> synCompanyList = synCompanyAccountService.findByBizIdListAndType(CollectionUtils.removeDuplication(supplierIdList), 1);
        List<String> clientIdList = new ArrayList<>();
        synCompanyList.forEach(synCompanyAccount -> {
            synCompanyMap.put(synCompanyAccount.getBizId(), synCompanyAccount);
            clientIdList.add(synCompanyAccount.getClientId());
        });

        List<SynCompanyAccountSetting> synCompanySettingList = synCompanySettingService.findByClientIdList(clientIdList, EdiCommCodes.PLACE_TRADE_ORDER);
        return EntityUtils.getStringKeyMapFromBeans(synCompanySettingList, "clientId");
    }


    @Override
    public int processOriginalAndSave(LogisticsRequest dto) {
        Date messageTime;

        EventHead eventHead = dto.getEventHead();
        String messageTimeStr = eventHead.getEventTime();
        messageTime = DateUtils.parseDetailDateTime(messageTimeStr);
        //保存原始的消息
        OrdTrackingOriginal trackingOriginal = new OrdTrackingOriginal();
        trackingOriginal.setToken(eventHead.getToken());
        trackingOriginal.setConvertStatus(ConvertStatus.TOBE_CONVERT);
        trackingOriginal.setEventCode(eventHead.getEventCode());
        trackingOriginal.setEventSource(eventHead.getEventSource());
        trackingOriginal.setEventTarget(eventHead.getEventTarget());
        trackingOriginal.setTrackingReport(JsonUtils.toJSONString(dto));
        trackingOriginal.setEventTime(messageTime);
        return trackingOriginalService.save(trackingOriginal);
    }

    /**
     * 根据id更新转换的状态
     *
     * @param originalId    要更新记录的id
     * @param convertStatus 状态
     */
    @Override
    public void updateConvertStatus(int originalId, ConvertStatus convertStatus) {
        trackingOriginalService.updateConvertStatus(originalId, convertStatus);
    }


    private void judgeVaild(ReceGoodOrder receGoodOrder) {
      String orderNo =   orderService.findOrderNoByWaybillNo(receGoodOrder.getWaybillNo());
        List<String> subOrderNos = subOrderService.findSubOrderNoByOrderNo(orderNo);
        if (subOrderNos.size() != receGoodOrder.getSubOrder().size()) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "数据异常");
        }
        for (SubOrder receSubOrderDto : receGoodOrder.getSubOrder()) {
            if (!subOrderNos.contains(receSubOrderDto.getSubOrderNo())) {
                String message = "子订单号:" + receSubOrderDto.getSubOrderNo() + "，不存在！";
                throw Exceptions.bizException(EdiErrorCodes.ERROR_EDI_ORD_TRACKING_SUBWAYBILLNO_ERROR, message);
            }
            if (receSubOrderDto.getCargoNumber() == null || receSubOrderDto.getCargoNumber() <= 0) {
                String message = "子订单:" + receSubOrderDto.getSubOrderNo() + ",的cargoNumber不能为空并且应大于0";
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, message);
            }
            if (receSubOrderDto.getLength() == null || receSubOrderDto.getLength().longValue() <= 0) {
                String message = "子订单:" + receSubOrderDto.getSubOrderNo() + ",的length不能为空并且应大于0";
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, message);
            }
            if (receSubOrderDto.getWidth() == null || receSubOrderDto.getWidth().longValue() <= 0) {
                String message = "子订单:" + receSubOrderDto.getSubOrderNo() + ",的width不能为空并且应大于0";
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, message);
            }
            if (receSubOrderDto.getHeight() == null || receSubOrderDto.getHeight().longValue() <= 0) {
                String message = "子订单:" + receSubOrderDto.getSubOrderNo() + ",的height不能为空并且应大于0";
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, message);
            }
            if (receSubOrderDto.getWeight() == null || receSubOrderDto.getWeight().longValue() <= 0) {
                String message = "子订单:" + receSubOrderDto.getSubOrderNo() + ",的weight不能为空并且应大于0";
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, message);
            }
        }
    }

}
